//! 简单文本输出协议，为基于文本的 ConsoleOut 设备定义了最小需求集。

use crate::{
    guid_struct, {EfiGuid, EfiStatus},
};

pub type Reset = extern "efiapi" fn(
    this: *mut EfiSimpleTextOutputProtocol,
    extended_verification: bool,
) -> EfiStatus;

pub type EfiTextString =
    extern "efiapi" fn(this: *mut EfiSimpleTextOutputProtocol, string: *const u16);

pub type EfiTextTestString =
    extern "efiapi" fn(this: *mut EfiSimpleTextOutputProtocol, string: *const u16);

pub type EfiTextQueryMode = extern "efiapi" fn(
    this: *mut EfiSimpleTextOutputProtocol,
    mode_number: usize,
    columns: *mut usize,
    rows: *mut usize,
);

pub type EfiTextSetMode =
    extern "efiapi" fn(this: *mut EfiSimpleTextOutputProtocol, mode_number: usize);

pub type EfiTextSetAttribute =
    extern "efiapi" fn(this: *mut EfiSimpleTextOutputProtocol, attribute: usize);

pub type EfiTextClearScreen = extern "efiapi" fn(this: *mut EfiSimpleTextOutputProtocol);

pub type EfiTExtSetCursorPosition =
    extern "efiapi" fn(this: *mut EfiSimpleTextOutputProtocol, column: usize, row: usize);

pub type EfiTextEnableCursor =
    extern "efiapi" fn(this: *mut EfiSimpleTextOutputProtocol, visible: bool);

/// 该结构体中的所有字段都是只读，并且只能通过特定的接口函数来更改。
pub struct SimpleTextOutputMode {
    /// query_mode() 和 set_mode() 所支持的最大模式号
    pub max_mode: i32,
    /// 输出设备的当前文本模式
    pub mode: i32,
    pub attribute: i32,
    pub cursor_column: i32,
    pub cursor_row: i32,
    pub cursor_visible: bool,
}
/// 任何支持 ConsoleOut 或 StandardError 的设备至少需要支持该协议。
/// 除此之外，这类设备的文本模式至少要支持 80 x 25 个字符。
///
/// 只支持图形模式的视频设备要求能够模拟文本模式的功能。
/// 输出字符串中的控制字符只能使用定义在 [`unicode_control_characters`](super::unicode_control_characters) 中的控制字符。
///
/// 如果输出设备在 `EFI_BOOT_SERVICES.HandleProtocol()` 调用时不在有效文本模式，设备会指示当前模式号为 -1。
/// 一旦连接到输出设备，调用者需要验证输出设备的模式，并且如果当前模式不可接受则需要设置成可用的模式。
pub struct EfiSimpleTextOutputProtocol {
    /// 复位输入设备（硬件上）
    /// 复位操作会清空驻留在内存中的任何（用于缓冲按键数据的）输入队列，并将输入流置于已知的空状态。
    ///
    /// 作为初始化的一部分，固件或设备会快速的进行设备验证，以便判断设备是否工作。
    ///
    /// ### 参数
    /// extended_verification: 用来指示驱动在复位期间是否执行更多的验证操作。
    ///
    /// ### 返回的状态码
    /// + EFI_SUCCESS: 设备成功复位
    /// + EFI_DEVICE_ERROR: 设备工作不正常，并且不能够被复位。
    pub reset: Reset,
    /// 将字符串写入到输出设备中
    ///
    /// 这是输出设备的最基本的输出机制。字符串会被显式在输出设备的当前游标位置，并且游标会根据
    /// [`unicode_control_characters`](super::unicode_control_characters) 中的控制符移动游标
    /// 如果没有控制字符，则默认在当前有标位置打印字符，并且游标向右移动一列。
    /// 如果有超过了显式设备的右边缘，则会移动到下一行的开始，相当于插入一个 CR 和一个 LF 字符。
    /// 如果游标在显式设备的底部，则先换行，然后设备滚动一行。
    ///
    /// ### 参数
    /// + this：指向 [`EfiSimpleTextOutputProtocol`] 实列的指针。
    /// + string: 在输出设备上显式的以 null 结尾的字符串。所有的输出设备必须也支持 Unicode 图形字符码。
    ///
    /// ### 返回的状态码
    /// + EFI_SUCCESS: 字符串被成功输出到设备中
    /// + EFI_DEVICE_ERROR: 当尝试输出文本时，设备报告了一个错误
    /// + EFI_UNSUPPORTED: 输出设备的模式不受支持
    /// + EFI_WARN_UNKNOWN_GLYPH：该警告码表示字符串中的一些字符无法被渲染，并且被跳过。
    pub output_string: EfiTextString,
    /// 测试字符串中的所有字符是否可以输出到目标设备中。
    ///
    /// ### 参数
    /// + string: 待检查的以 null 结尾的字符串。
    ///
    /// ### 返回的状态码
    /// + EFI_SUCCESS: 设备可以渲染输出字符串
    /// + EFI_UNSUPPORTED： 部分字符无法被设备渲染
    pub test_string: EfiTextTestString,
    /// 返回输出设备对可获得的文本模式的支持信息。
    ///
    /// 所有的输出设备至少支持 80x25 的文本模式，该模式的定义为模式 0。
    /// 如果输出设备支持 80x50，该模式定义为模式 1.
    /// 所有其他受支持的文本维度的模式号 >= 2。
    /// 如果输出设备支持模式号 >= 2 的模式，但不支持 80x25 模式，则查询模式 1 会返回 `EFI_UNSUPPORTED`
    ///
    /// ### 参数
    /// + this：指向 [`EfiSimpleTextOutputProtocol`] 实例
    /// + mode_number： 返回信息所依赖的模式
    /// + columns、rows：返回所请求的模式中输出设备文本几何。
    ///
    /// ### 返回的状态码
    /// + EFI_SUCCESS: 请求的模式信息被返回
    /// + EFI_DEVICE_ERROR: 设备出错并且不能完成请求
    /// + EFI_UNSUPPORTED: 模式号无效
    pub query_mode: EfiTextQueryMode,
    /// 将输出设备设为特定的文本模式
    ///
    /// 一旦设置成功，设备将处于请求模式下的几何体中，并且设备会在 (0,0) 处被清除为当前背景色。
    ///
    /// ### 参数
    /// + this: 指向 `EfiSimpleTextOutputProtocol` 实例的指针。
    /// + 需要设置的文本模式
    ///
    /// ### 返回的状态码
    /// + EFI_SUCCESS: 请求的文本模式被设置
    /// + EFI_DEVICE_ERROR: 设备出错，并且无法完成请求
    /// + EFI_UNSUPPORTED: 模式号无效
    pub set_mode: EfiTextSetMode,

    /// 为 `output_string` 和 `clear_screen` 函数设置背景色和前景色。
    ///
    /// 即便在无效文本模式下仍可以设置颜色掩码。
    /// 支持不同数量的文本模式的设备需要模拟 [`attribute`](super::attribute) 下所有颜色，以最大限度的发挥设备能力。
    ///
    /// ### 参数
    /// + this: 指向 `EfiSimpleTextOutputProtocol` 实例的指针。
    /// + attribute: 需要设置的属性，bits 0..3 为前景色，bits 4..6 为背景色，其他 bits 是保留的。
    ///
    /// ### 返回的状态码
    /// + EFI_SUCCESS: 请求的属性被设置成功
    /// + EFI_DEVICE_ERROR: 设备出错，并且不能完成请求
    pub set_attribute: EfiTextSetAttribute,
    /// clear_screen() 函数清除当前输出显式，并将设为当前所选择的背景色。游标位置设为 (0,0)。
    ///
    /// ### 参数
    /// + this: 指向 `EfiSimpleTextOutputProtocol` 实例的指针
    ///
    /// ### 返回的状态码
    /// + EFI_SUCCESS: 操作完全成功
    /// + EFI_DEVICE_ERROR: 设备出错，且无法完成请求
    /// + EFI_UNSUPPORTED: 设备不在有效的文本模式下
    pub clear_screen: EfiTextClearScreen,
    /// 设置游标位置的当前坐标，屏幕左上角被定义为坐标轴 (0,0)
    ///
    /// ### 参数
    /// + this: 指向 `EfiSimpleTextOutputProtocol` 的实例
    /// + column, row: 游标所要设置的位置。必须大于或等于 0，并且小于 query_mode() 所返回的行列数
    ///
    /// ### 返回的状态码
    /// + EFI_SUCCESS: 操作完全成功
    /// + EFI_DEVICE_ERROR: 设备出错，并且不能完成请求
    /// + EFI_UNSUPPORTED: 输出设备不在有效的文本模式下，或者游标位置在当前模式下无效。
    pub set_cursor_position: EfiTExtSetCursorPosition,
    /// 将游标设为可见或者不可见
    ///
    /// ### 参数
    /// + this: 指向 `EfiSimpleTextOutputProtocol` 实例的指针
    /// + visible: 如果为 `true` 则将游标设为可见，如果为 `false` 则将游标设为不可见
    ///
    /// ### 返回的状态码
    /// + EFI_SUCCESS: 操作完全成功
    /// + EFI_DEVICE_ERROR: 设备出错，且不能完成请求，或者设备不支持改变游标模式
    /// + EFI_UNSUPPORTED: 输出设备不支持游标的可见性控制。
    pub enable_cursor: EfiTextEnableCursor,
    pub mode: *mut SimpleTextOutputMode,
}

impl EfiSimpleTextOutputProtocol {
    pub const GUID: EfiGuid =
        guid_struct! {0x387477c2,0x69c7,0x11d2, {0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b}};
}
